;*******************************************************************************
; (C) 2006 Keith S. Robertson - IE.LIB
;-------------------------------------------------------------------------------
;
; Library for handling access to Infinity Engine game files. 
;
; Infinity Engine (IE) games are:
;
; - Baldurs Gate (The Original Saga)
; - Baldurs Gate: Tales of The Sword Coast
; - Baldurs Gate II: Shadows of Amn
; - Baldurs Gate II: Throne of Bhaal
; - Icewind Dale
; - Icewind Dale: Heart of Winter
; - Icewind Dale: HoW: Trials of The Luremaster
; - Icewind Dale II
; - Planescape Torment
;
;*******************************************************************************

;-------------------------------------------------------------------------------
; Setup
;-------------------------------------------------------------------------------
.386	
.MODEL FLAT, STDCALL

INCLUDE WINDOWS.INC
INCLUDE KERNEL32.INC
INCLUDE advapi32.inc
INCLUDE USER32.INC
INCLUDE MASM32.INC

INCLUDELIB KERNEL32.LIB
INCLUDELIB USER32.LIB
includelib advapi32.lib	
INCLUDELIB MASM32.LIB

INCLUDE IE.MAC			; IE Macros Used Throughtout Library

;-------------------------------------------------------------------------------
; Source for each definite IE file type that library will handle
;-------------------------------------------------------------------------------
INCLUDE IE.INC			; IE Root 
INCLUDE IE_KEY.INC		; KEY Files Include
INCLUDE IE_KEY.ASM		; KEY Files Source
INCLUDE IE_BIF.INC		; BIF Files Include
INCLUDE IE_BIF.ASM		; BIF Files Source

;-------------------------------------------------------------------------------
; Constants
;-------------------------------------------------------------------------------
.CONST




;-------------------------------------------------------------------------------
; Static Data
;-------------------------------------------------------------------------------

.DATA
	ErrorBuffer		db 260 dup (0) 
	LibName			db	"IE.LIB",0
	LibCopyright	db	"(C) 2006 Keith S. Robertson",0
	IE_PATH_BUFFER	db 	MAX_PATH dup (0)

;-------------------------------------------------------------------------------
; Dynamic Data
;-------------------------------------------------------------------------------
.DATA?


;-------------------------------------------------------------------------------
; Main Code
;-------------------------------------------------------------------------------
.CODE


DllEntry  proc hInstDLL:DWORD, reason:DWORD, unused:DWORD
    .if reason == DLL_PROCESS_ATTACH
        mov eax, TRUE
        ; -----------------------------
        ; If error at startup, return 0
        ; System will abort loading DLL
        ; -----------------------------

    .elseif reason == DLL_PROCESS_DETACH

    .elseif reason == DLL_THREAD_ATTACH

    .elseif reason == DLL_THREAD_DETACH
        
    .endif
	ret
DllEntry endp


;-------------------------------------------------------------------------------
; IE Open File - Opens Infinity Engine File
;-------------------------------------------------------------------------------
IEOpenFile PROC IEFileName:DWORD
	Invoke CreateFile, IEFileName, GENERIC_READ+GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS,NULL
	.IF eax == INVALID_HANDLE_VALUE
		;Err 'Failed To Open Infinity Engine File'
	.endif
	Ret
IEOpenFile ENDP
;*******************************************************************************

;-------------------------------------------------------------------------------
; IE Close File - Closes Infinity Engine File
;-------------------------------------------------------------------------------
IECloseFile PROC hIEFile:DWORD
	Invoke CloseHandle, hIEFile
	.IF eax == 0
		;Err 'Failed To Close Infinity Engine File'
	.endif
	RET
IECloseFile ENDP
;*******************************************************************************

;-------------------------------------------------------------------------------
; IE File Signature - Reads signature bytes from header of file
;-------------------------------------------------------------------------------
IEFileSignature PROC hFile_or_pMem:DWORD, pBuffer:DWORD, AccessType:DWORD
	LOCAL hFile:DWORD
	LOCAL pMem:DWORD
	LOCAL lnBytesRead:DWORD
		
	mov eax, hFile_or_pMem
	
	.IF AccessType == IE_ACCESS_FILE	; 0 
		mov hFile, eax
		Invoke SetFilePointerEx, hFile, 0, NULL, NULL, FILE_BEGIN
		Invoke ReadFile, hFile, pBuffer, 4, Addr lnBytesRead, NULL
		.if eax != 0
			mov eax, TRUE		
		.else
			mov eax, FALSE
		.endif
		
	.else	; BIF_ACCESS_MEM ; 1
		mov pMem, eax
		lea ebx, pMem
		Invoke MemCopy, pBuffer, ebx, 4
		mov eax, TRUE
	.endif
	mov eax, TRUE
	ret
IEFileSignature ENDP

;*******************************************************************************

;-------------------------------------------------------------------------------
; IE File Version - Reads version of file format from header of file
;-------------------------------------------------------------------------------
IEFileVersion PROC hFile_or_pMem:DWORD, pBuffer:DWORD, AccessType:DWORD
	LOCAL hFile:DWORD
	LOCAL pMem:DWORD
	LOCAL lnBytesRead:DWORD
		
	mov eax, hFile_or_pMem
	
	.IF AccessType == BIF_ACCESS_FILE	; 0 
		mov hFile, eax
		Invoke SetFilePointerEx, hFile, 4, NULL, NULL, FILE_BEGIN
		Invoke ReadFile, hFile, pBuffer, 4, Addr lnBytesRead, NULL
		.if eax != 0
			mov eax, TRUE		
		.else
			mov eax, FALSE
		.endif
		
	.else	; BIF_ACCESS_MEM ; 1
		mov pMem, eax
		lea ebx, pMem
		add ebx, 4
		Invoke MemCopy, pBuffer, ebx, 4
		mov eax, TRUE
	.endif
	mov eax, TRUE
	ret
	ret
IEFileVersion ENDP	
;*******************************************************************************


IEDetectGames	PROC	pIEGamesStruct:DWORD
	LOCAL hRegKey:DWORD
	LOCAL lnRegType:DWORD
	LOCAL lnRegDataBufferSize:DWORD
	
	; =======================
	; BG1 - Original Saga
	; =======================
	
	; Detect if game is installed: BG1 - Original Saga
	Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Bioware Corp.\Baldur's Gate\1.01.4315"), 0, KEY_READ, Addr hRegKey

	.IF eax == ERROR_SUCCESS ; Open reg key for this game. If opened ok then game is installed so proceed to next steps
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, TRUE	; Yes game is installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_INSTALLED, edx ; And save this to structure in memory   

		; Get path of installed game 
		Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\BGMain.exe"), 0, KEY_ALL_ACCESS, Addr hRegKey

		.iF eax == ERROR_SUCCESS ; Open reg key for this game path. If opened ok, then we will need to read it - next steps
			mov lnRegDataBufferSize, MAX_PATH ; Set buffer size for RegQueryValueEx - same as 256 maximum path size
			
			; Query value of path for this opened key and read value into buffer
			Invoke RegQueryValueEx, hRegKey, CTEXT("Path"), 0, Addr lnRegType, Addr IE_PATH_BUFFER, Addr lnRegDataBufferSize
			.if eax == ERROR_SUCCESS ; If reg key read ok, then store the value read in structure memory
				;PrintDec hRegKey, "Query Value"
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_PATH ; Load offset to BG1_SAGA_PATH in edx
								
				Invoke lstrcpyn, edx, Addr IE_PATH_BUFFER, lnRegDataBufferSize ; Copy buffer to game path in structure
				.if eax == NULL
					Err 'Failed BG1-Saga'
				.endif

			.else ; Couldnt read reg so nullify string in structure memory just in case
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				; Effectively nullify string, so no old data is ever read by mistake
				mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_PATH, BYTE PTR 0  ; And save this to structure in memory  
			.endif

		.else ; Couldnt get path of installed game even thought it seems installed. So nullify string in structure memory just in case
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			; Effectively nullify string, so no old data is ever read by mistake
			mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_PATH, BYTE PTR 0 ; And save this to structure in memory  
		.endif
				
	.else ; Game not detected so set structure appropriately for this.
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, FALSE	; No game is not installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_INSTALLED, edx ; And save this to structure in memory   
		
		mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
		; Effectively nullify string, so no old data is ever read by mistake
		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_PATH, BYTE PTR 0 ; And save this to structure in memory  
	.endif

	; =======================
	; BG1 - TOTSC
	; =======================

	; Detect if game is installed: BG1 - Tales of The Sword Coast
	Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Bioware Corp.\Baldur's Gate\1.03.5500"), 0, KEY_READ, Addr hRegKey

	.IF eax == ERROR_SUCCESS ; Open reg key for this game. If opened ok then game is installed so proceed to next steps
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, TRUE	; Yes game is installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_TOTSC_INSTALLED, edx ; And save this to structure in memory   
		
		; Check if BG1 Original Saga is installed as this shares the same path as it
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_INSTALLED 
		.IF edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_PATH ; Load offset to BG1_SAGA_PATH in edx
			lea eax, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_TOTSC_PATH ; Load offset to BG1_TOTSC_PATH in eax								
			Invoke lstrcpyn, eax, edx, MAX_PATH ; Copy to game path in structure
			.if eax == NULL
				Err 'Failed To Copy BG1-Saga Path To BG1-ToTSC Path'
			.endif
		.else ; actually an error at this point as ToTSC should not be installed without BG1 - To add code here regarding this at later date
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			; Effectively nullify string, so no old data is ever read by mistake
			mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_TOTSC_PATH, BYTE PTR 0 ; And save this to structure in memory  
		.endif

	.else ; Game not detected so set structure appropriately for this.
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, FALSE	; No game is not installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_TOTSC_INSTALLED, edx ; And save this to structure in memory   
		
		mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
		; Effectively nullify string, so no old data is ever read by mistake
		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_TOTSC_PATH, BYTE PTR 0 ; And save this to structure in memory  
	.endif


	; =======================
	; BG2 - Shadows of Amn
	; =======================
	
	; Detect if game is installed: BG2 - Shadows of Amn
	Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\BioWare Corp\Baldur's Gate(TM) II - Shadows of Amn(TM)\1.00.000"), 0, KEY_READ, Addr hRegKey

	.IF eax == ERROR_SUCCESS ; Open reg key for this game. If opened ok then game is installed so proceed to next steps
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, TRUE	; Yes game is installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_INSTALLED, edx ; And save this to structure in memory   

		; Get path of installed game 
		Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\BG2Main.exe"), 0, KEY_ALL_ACCESS, Addr hRegKey

		.iF eax == ERROR_SUCCESS ; Open reg key for this game path. If opened ok, then we will need to read it - next steps
			mov lnRegDataBufferSize, MAX_PATH ; Set buffer size for RegQueryValueEx - same as 256 maximum path size
			
			; Query value of path for this opened key and read value into buffer
			Invoke RegQueryValueEx, hRegKey, CTEXT("Path"), 0, Addr lnRegType, Addr IE_PATH_BUFFER, Addr lnRegDataBufferSize
			.if eax == ERROR_SUCCESS ; If reg key read ok, then store the value read in structure memory
				;PrintDec hRegKey, "Query Value"
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_PATH ; Load offset to BG2_SOA_PATH in edx
								
				Invoke lstrcpyn, edx, Addr IE_PATH_BUFFER, lnRegDataBufferSize ; Copy buffer to game path in structure
				.if eax == NULL
					Err 'Failed BG2-SOA'
				.endif

			.else ; Couldnt read reg so nullify string in structure memory just in case
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				; Effectively nullify string, so no old data is ever read by mistake
				mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_PATH, BYTE PTR 0  ; And save this to structure in memory  
			.endif

		.else ; Couldnt get path of installed game even thought it seems installed. So nullify string in structure memory just in case
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			; Effectively nullify string, so no old data is ever read by mistake
			mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_PATH, BYTE PTR 0 ; And save this to structure in memory  
		.endif
				
	.else ; Game not detected so set structure appropriately for this.
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, FALSE	; No game is not installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_INSTALLED, edx ; And save this to structure in memory   
		
		mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
		; Effectively nullify string, so no old data is ever read by mistake
		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_PATH, BYTE PTR 0 ; And save this to structure in memory  
	.endif

	; =======================
	; BG2 - Throne of Bhaal
	; =======================

	; Detect if game is installed: BG2 - Throne of Bhaal
	Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\BioWare Corp\Baldur's Gate(TM) II - Throne of Bhaal (TM)\1.00.000"), 0, KEY_READ, Addr hRegKey

	.IF eax == ERROR_SUCCESS ; Open reg key for this game. If opened ok then game is installed so proceed to next steps
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, TRUE	; Yes game is installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_TOB_INSTALLED, edx ; And save this to structure in memory   
		
		; Check if BG1 Original Saga is installed as this shares the same path as it
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_INSTALLED 
		.IF edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_PATH ; Load offset to BG2_SOA_PATH in edx
			lea eax, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_TOB_PATH ; Load offset to BG2_TOB_PATH in eax								
			Invoke lstrcpyn, eax, edx, MAX_PATH ; Copy to game path in structure
			.if eax == NULL
				Err 'Failed To Copy BG2-SOA Path To BG2-TOB Path'
			.endif
		.else ; actually an error at this point as BG2-TOB should not be installed without BG2-SOA - To add code here regarding this at later date
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			; Effectively nullify string, so no old data is ever read by mistake
			mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_TOB_PATH, BYTE PTR 0 ; And save this to structure in memory    
		.endif

	.else ; Game not detected so set structure appropriately for this.
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, FALSE	; No game is not installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_TOB_INSTALLED, edx ; And save this to structure in memory   
		
		mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
		; Effectively nullify string, so no old data is ever read by mistake
		mov (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_TOB_PATH, BYTE PTR 0 ; And save this to structure in memory  
	.endif


	; =======================
	; IWD1 - Icewind Dale
	; =======================
	
	; Detect if game is installed: IWD1 - Icewind Dale
	Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Black Isle\Icewind Dale\1.00.000"), 0, KEY_READ, Addr hRegKey

	.IF eax == ERROR_SUCCESS ; Open reg key for this game. If opened ok then game is installed so proceed to next steps
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, TRUE	; Yes game is installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_INSTALLED, edx ; And save this to structure in memory   

		; Get path of installed game 
		Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\IDMain.exe"), 0, KEY_ALL_ACCESS, Addr hRegKey

		.iF eax == ERROR_SUCCESS ; Open reg key for this game path. If opened ok, then we will need to read it - next steps
			mov lnRegDataBufferSize, MAX_PATH ; Set buffer size for RegQueryValueEx - same as 256 maximum path size
			
			; Query value of path for this opened key and read value into buffer
			Invoke RegQueryValueEx, hRegKey, CTEXT("Path"), 0, Addr lnRegType, Addr IE_PATH_BUFFER, Addr lnRegDataBufferSize
			.if eax == ERROR_SUCCESS ; If reg key read ok, then store the value read in structure memory
				;PrintDec hRegKey, "Query Value"
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_PATH ; Load offset to BG2_SOA_PATH in edx
								
				Invoke lstrcpyn, edx, Addr IE_PATH_BUFFER, lnRegDataBufferSize ; Copy buffer to game path in structure
				.if eax == NULL
					Err 'Failed IWD1'
				.endif

			.else ; Couldnt read reg so nullify string in structure memory just in case
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				; Effectively nullify string, so no old data is ever read by mistake
				mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_PATH, BYTE PTR 0  ; And save this to structure in memory  
			.endif

		.else ; Couldnt get path of installed game even thought it seems installed. So nullify string in structure memory just in case
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			; Effectively nullify string, so no old data is ever read by mistake
			mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_PATH, BYTE PTR 0 ; And save this to structure in memory  
		.endif
				
	.else ; Game not detected so set structure appropriately for this.
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, FALSE	; No game is not installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_INSTALLED, edx ; And save this to structure in memory   
		
		mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
		; Effectively nullify string, so no old data is ever read by mistake
		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_PATH, BYTE PTR 0 ; And save this to structure in memory  
	.endif

	; =======================
	; IWD1 - Heart of Winter
	; =======================

	; Detect if game is installed: IWD1 - Heart of Winter
	Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Black Isle\Icewind Dale - Heart of Winter\1.00.000"), 0, KEY_READ, Addr hRegKey

	.IF eax == ERROR_SUCCESS ; Open reg key for this game. If opened ok then game is installed so proceed to next steps
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, TRUE	; Yes game is installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_HOW_INSTALLED, edx ; And save this to structure in memory   
		
		; Check if BG1 Original Saga is installed as this shares the same path as it
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_INSTALLED 
		.IF edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_PATH ; Load offset to IWD1_PATH in edx
			lea eax, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_HOW_PATH ; Load offset to IWD1_HOW_PATH in eax								
			Invoke lstrcpyn, eax, edx, MAX_PATH ; Copy to game path in structure
			.if eax == NULL
				Err 'Failed To Copy IWD1 Path To IWD1-HOW Path'
			.endif
		.else ; actually an error at this point as IWD1-HOW should not be installed without IWD1 - To add code here regarding this at later date
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			; Effectively nullify string, so no old data is ever read by mistake
			mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_HOW_PATH, BYTE PTR 0 ; And save this to structure in memory  
		.endif

	.else ; Game not detected so set structure appropriately for this.
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, FALSE	; No game is not installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_HOW_INSTALLED, edx ; And save this to structure in memory   
		
		mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
		; Effectively nullify string, so no old data is ever read by mistake
		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_HOW_PATH, BYTE PTR 0 ; And save this to structure in memory  
	.endif


	; ====================================
	; IWD1 - HOW - Trial of The Luremaster
	; ====================================

	; Detect if game is installed: IWD1 - HOW - Trial of The Luremaster
	Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Black Isle\Icewind Dale - Heart of Winter: Trials of the Luremaster\1.00.000"), 0, KEY_READ, Addr hRegKey

	.IF eax == ERROR_SUCCESS ; Open reg key for this game. If opened ok then game is installed so proceed to next steps
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, TRUE	; Yes game is installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_TOTL_INSTALLED, edx ; And save this to structure in memory   
		
		; Check if BG1 Original Saga is installed as this shares the same path as it
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_INSTALLED 
		.IF edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_PATH ; Load offset to IWD1_PATH in edx
			lea eax, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_TOTL_PATH ; Load offset to IWD1_HOW_PATH in eax								
			Invoke lstrcpyn, eax, edx, MAX_PATH ; Copy to game path in structure
			.if eax == NULL
				Err 'Failed To Copy IWD1 Path To IWD1-ToTL Path'
			.endif
		.else ; actually an error at this point as IWD1-ToTL should not be installed without IWD1 or IWD1-HoW - To add code here regarding this at later date
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			; Effectively nullify string, so no old data is ever read by mistake
			mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_TOTL_PATH, BYTE PTR 0 ; And save this to structure in memory  
		.endif

	.else ; Game not detected so set structure appropriately for this.
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, FALSE	; No game is not installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_TOTL_INSTALLED, edx ; And save this to structure in memory   
		
		mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
		; Effectively nullify string, so no old data is ever read by mistake
		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_TOTL_PATH, BYTE PTR 0 ; And save this to structure in memory  
	.endif


	; =======================
	; IWD2 - Icewind Dale II
	; =======================
	
	; Detect if game is installed: IWD2 - Icewind Dale II
	Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Black Isle\Icewind Dale II\1.00.000"), 0, KEY_READ, Addr hRegKey

	.IF eax == ERROR_SUCCESS ; Open reg key for this game. If opened ok then game is installed so proceed to next steps
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, TRUE	; Yes game is installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD2_INSTALLED, edx ; And save this to structure in memory   

		; Get path of installed game 
		Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\IWD2.exe"), 0, KEY_ALL_ACCESS, Addr hRegKey

		.iF eax == ERROR_SUCCESS ; Open reg key for this game path. If opened ok, then we will need to read it - next steps
			mov lnRegDataBufferSize, MAX_PATH ; Set buffer size for RegQueryValueEx - same as 256 maximum path size
			
			; Query value of path for this opened key and read value into buffer
			Invoke RegQueryValueEx, hRegKey, CTEXT("Path"), 0, Addr lnRegType, Addr IE_PATH_BUFFER, Addr lnRegDataBufferSize
			.if eax == ERROR_SUCCESS ; If reg key read ok, then store the value read in structure memory
				;PrintDec hRegKey, "Query Value"
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD2_PATH ; Load offset to BG1_SAGA_PATH in edx
								
				Invoke lstrcpyn, edx, Addr IE_PATH_BUFFER, lnRegDataBufferSize ; Copy buffer to game path in structure
				.if eax == NULL
					Err 'failed'
				.endif

			.else ; Couldnt read reg so nullify string in structure memory just in case
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				; Effectively nullify string, so no old data is ever read by mistake
				mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD2_PATH, BYTE PTR 0  ; And save this to structure in memory  
			.endif

		.else ; Couldnt get path of installed game even thought it seems installed. So nullify string in structure memory just in case
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			; Effectively nullify string, so no old data is ever read by mistake
			mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD2_PATH, BYTE PTR 0 ; And save this to structure in memory  
		.endif
				
	.else ; Game not detected so set structure appropriately for this.
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, FALSE	; No game is not installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD2_INSTALLED, edx ; And save this to structure in memory   
		
		mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
		; Effectively nullify string, so no old data is ever read by mistake
		mov (INFINITY_ENGINE_GAMES PTR [ebx]).IWD2_PATH, BYTE PTR 0 ; And save this to structure in memory  
	.endif
	
	
	; ========================
	; PST - Planescape Torment
	; ========================
	
	; Detect if game is installed: BG1 - Original Saga
	Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Black Isle\Planescape - Torment\1.00.000"), 0, KEY_READ, Addr hRegKey

	.IF eax == ERROR_SUCCESS ; Open reg key for this game. If opened ok then game is installed so proceed to next steps
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, TRUE	; Yes game is installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).PST_INSTALLED, edx ; And save this to structure in memory   

		; Get path of installed game 
		Invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE, CTEXT("SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Torment.exe"), 0, KEY_ALL_ACCESS, Addr hRegKey

		.iF eax == ERROR_SUCCESS ; Open reg key for this game path. If opened ok, then we will need to read it - next steps
			mov lnRegDataBufferSize, MAX_PATH ; Set buffer size for RegQueryValueEx - same as 256 maximum path size
			
			; Query value of path for this opened key and read value into buffer
			Invoke RegQueryValueEx, hRegKey, CTEXT("Path"), 0, Addr lnRegType, Addr IE_PATH_BUFFER, Addr lnRegDataBufferSize
			.if eax == ERROR_SUCCESS ; If reg key read ok, then store the value read in structure memory
				;PrintDec hRegKey, "Query Value"
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).PST_PATH ; Load offset to BG1_SAGA_PATH in edx
								
				Invoke lstrcpyn, edx, Addr IE_PATH_BUFFER, lnRegDataBufferSize ; Copy buffer to game path in structure
				.if eax == NULL
					Err 'Failed PST'
				.endif

			.else ; Couldnt read reg so nullify string in structure memory just in case
				mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
				; Effectively nullify string, so no old data is ever read by mistake
				mov (INFINITY_ENGINE_GAMES PTR [ebx]).PST_PATH, BYTE PTR 0  ; And save this to structure in memory  
			.endif

		.else ; Couldnt get path of installed game even thought it seems installed. So nullify string in structure memory just in case
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			; Effectively nullify string, so no old data is ever read by mistake
			mov (INFINITY_ENGINE_GAMES PTR [ebx]).PST_PATH, BYTE PTR 0 ; And save this to structure in memory  
		.endif
				
	.else ; Game not detected so set structure appropriately for this.
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
 		mov edx, FALSE	; No game is not installed, so save this flag in structure
 		mov (INFINITY_ENGINE_GAMES PTR [ebx]).PST_INSTALLED, edx ; And save this to structure in memory   
		
		mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
		; Effectively nullify string, so no old data is ever read by mistake
		mov (INFINITY_ENGINE_GAMES PTR [ebx]).PST_PATH, BYTE PTR 0 ; And save this to structure in memory  
	.endif	



	mov eax, TRUE	
	ret

IEDetectGames endp


IEIsGameInstalled	PROC	pIEGamesStruct:DWORD, IEGame:DWORD
	
	
	mov eax, IEGame
	.IF eax == BG1_SAGA
		
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_INSTALLED
		.if edx == TRUE
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == BG1_TOTSC 
		
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_TOTSC_INSTALLED
		.if edx == TRUE
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == BG2_SOA

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_INSTALLED
		.if edx == TRUE
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == BG2_TOB

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_TOB_INSTALLED
		.if edx == TRUE
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == IWD1

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_INSTALLED
		.if edx == TRUE
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == IWD1_HOW

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_HOW_INSTALLED
		.if edx == TRUE
			mov eax, TRUE
				
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == IWD1_TOTL

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_TOTL_INSTALLED
		.if edx == TRUE
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == IWD2

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD2_INSTALLED
		.if edx == TRUE
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == PST

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).PST_INSTALLED
		.if edx == TRUE
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	.ELSE
		mov eax, FALSE	
	.ENDIF
	
	ret

IEIsGameInstalled endp


IEGamePath		PROC	pIEGamesStruct:DWORD, IEGame:DWORD, pBuffer:DWORD
	
	
	mov eax, IEGame
	.IF eax == BG1_SAGA
		
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_INSTALLED
		.if edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_SAGA_PATH ; Load offset to IWD1_PATH in edx
			Invoke lstrcpyn, pBuffer, edx, MAX_PATH ; Copy to game path in structure		
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == BG1_TOTSC 
		
		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_TOTSC_INSTALLED
		.if edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG1_TOTSC_PATH ; Load offset to IWD1_PATH in edx
			Invoke lstrcpyn, pBuffer, edx, MAX_PATH ; Copy to game path in structure	
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == BG2_SOA

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_INSTALLED
		.if edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_SOA_PATH ; Load offset to IWD1_PATH in edx
			Invoke lstrcpyn, pBuffer, edx, MAX_PATH ; Copy to game path in structure	
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == BG2_TOB

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_TOB_INSTALLED
		.if edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).BG2_TOB_PATH ; Load offset to IWD1_PATH in edx
			Invoke lstrcpyn, pBuffer, edx, MAX_PATH ; Copy to game path in structure	
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == IWD1

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_INSTALLED
		.if edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_PATH ; Load offset to IWD1_PATH in edx
			Invoke lstrcpyn, pBuffer, edx, MAX_PATH ; Copy to game path in structure	
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == IWD1_HOW

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_HOW_INSTALLED
		.if edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_HOW_PATH ; Load offset to IWD1_PATH in edx
			Invoke lstrcpyn, pBuffer, edx, MAX_PATH ; Copy to game path in structure	
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == IWD1_TOTL

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_TOTL_INSTALLED
		.if edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD1_TOTL_PATH ; Load offset to IWD1_PATH in edx
			Invoke lstrcpyn, pBuffer, edx, MAX_PATH ; Copy to game path in structure	
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == IWD2

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD2_INSTALLED
		.if edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).IWD2_PATH ; Load offset to IWD1_PATH in edx
			Invoke lstrcpyn, pBuffer, edx, MAX_PATH ; Copy to game path in structure	
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	
	.ELSEIF eax == PST

		mov ebx, pIEGamesStruct	; Setup for easier usage by allowing us to use offsets of structure
		mov edx, (INFINITY_ENGINE_GAMES PTR [ebx]).PST_INSTALLED
		.if edx == TRUE
			mov ebx, pIEGamesStruct ; Setup for easier usage by allowing us to use offsets of structure
			lea edx, (INFINITY_ENGINE_GAMES PTR [ebx]).PST_PATH ; Load offset to IWD1_PATH in edx
			Invoke lstrcpyn, pBuffer, edx, MAX_PATH ; Copy to game path in structure	
			mov eax, TRUE
		.else
			mov eax, FALSE	
		.endif 
	.ELSE
		mov eax, FALSE	
	.ENDIF
	
	ret
IEGamePath		ENDP

END DllEntry

